/**
 * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
 * SPDX-License-Identifier: MIT
 */

import { FlowNodeErrorData } from '@flowgram.ai/form-core';
import { FlowDocumentOptions, FlowNodeTransformData, FlowNodeType } from '@flowgram.ai/document';
import { TransformData } from '@flowgram.ai/core';

import { type WorkflowLinesManager } from './workflow-lines-manager';
import { initFormDataFromJSON, toFormJSON } from './utils/flow-node-form-data';
import {
  LineColor,
  LineRenderType,
  onDragLineEndParams,
  WorkflowNodeJSON,
  WorkflowNodeMeta,
} from './typings';
import {
  type WorkflowLineEntity,
  type WorkflowLinePortInfo,
  type WorkflowNodeEntity,
  type WorkflowPortEntity,
} from './entities';

export const WorkflowDocumentOptions = Symbol('WorkflowDocumentOptions');

/**
 * 线条配置
 */
export interface WorkflowDocumentOptions extends FlowDocumentOptions {
  cursors?: {
    grab?: string;
    grabbing?: string;
  };
  /** 双向连接 */
  twoWayConnection?: boolean;
  /** 线条颜色 */
  lineColor?: Partial<LineColor>;
  /** 是否显示错误线条 */
  isErrorLine?: (
    fromPort: WorkflowPortEntity | undefined,
    toPort: WorkflowPortEntity | undefined,
    lines: WorkflowLinesManager
  ) => boolean;
  /** 是否错误端口 */
  isErrorPort?: (port: WorkflowPortEntity) => boolean;
  /** 是否禁用端口 */
  isDisabledPort?: (port: WorkflowPortEntity) => boolean;
  /** 是否反转线条箭头 */
  isReverseLine?: (line: WorkflowLineEntity) => boolean;
  /** 是否隐藏线条箭头 */
  isHideArrowLine?: (line: WorkflowLineEntity) => boolean;
  /** 是否流动线条 */
  isFlowingLine?: (line: WorkflowLineEntity) => boolean;
  /** 是否禁用线条 */
  isDisabledLine?: (line: WorkflowLineEntity) => boolean;
  /** 拖拽线条结束 */
  onDragLineEnd?: (params: onDragLineEndParams) => Promise<void>;
  /** 获取线条渲染器 */
  setLineRenderType?: (line: WorkflowLineEntity) => LineRenderType | undefined;
  /** 设置线条样式 */
  setLineClassName?: (line: WorkflowLineEntity) => string | undefined;
  /** 能否添加线条 */
  canAddLine?: (
    fromPort: WorkflowPortEntity,
    toPort: WorkflowPortEntity,
    lines: WorkflowLinesManager,
    silent?: boolean
  ) => boolean;
  /** 能否删除节点 */
  canDeleteNode?: (node: WorkflowNodeEntity, silent?: boolean) => boolean;
  /** 能否删除线条 */
  canDeleteLine?: (
    line: WorkflowLineEntity,
    newLineInfo?: Required<Omit<WorkflowLinePortInfo, 'data'>>,
    silent?: boolean
  ) => boolean;
  /**
   * @param fromPort - 开始点
   * @param oldToPort - 旧的连接点
   * @param newToPort - 新的连接点
   * @param lines - 线条管理器
   */
  canResetLine?: (
    oldLine: WorkflowLineEntity,
    newLineInfo: Required<WorkflowLinePortInfo>,
    lines: WorkflowLinesManager
  ) => boolean;
  /**
   * 是否允许拖入子画布 (loop or group)
   * Whether to allow dragging into the sub-canvas (loop or group)
   * @param params
   */
  canDropToNode?: (params: {
    dragNodeType?: FlowNodeType;
    dragNode?: WorkflowNodeEntity;
    dropNode?: WorkflowNodeEntity;
    dropNodeType?: FlowNodeType;
  }) => boolean;
}

export const WorkflowDocumentOptionsDefault: WorkflowDocumentOptions = {
  // cursors: {
  //   grab: 'url(""), auto',
  //   grabbing:
  //     'url(""), auto',
  // },

  fromNodeJSON(node, json, isFirstCreate) {
    initFormDataFromJSON(node, json, isFirstCreate);
    return;
  },
  toNodeJSON(node: WorkflowNodeEntity): WorkflowNodeJSON {
    const nodeError = node.getData<FlowNodeErrorData>(FlowNodeErrorData)?.getError();
    // 如果节点有错误，这里抛出错误，避免后面的代码执行异常
    if (nodeError) {
      throw nodeError;
    }
    const transform = node.getData<TransformData>(TransformData)!;

    let formJSON = toFormJSON(node);
    const metaData: Record<string, unknown> = {};

    // 持久化子画布位置
    const nodeMeta = node.getNodeMeta<WorkflowNodeMeta>();
    const subCanvas = nodeMeta.subCanvas?.(node);
    if (subCanvas?.isCanvas === false) {
      const canvasNodeTransform =
        subCanvas.canvasNode.getData<FlowNodeTransformData>(FlowNodeTransformData);
      const { x, y } = canvasNodeTransform.transform.position;
      metaData.canvasPosition = { x, y };
    }

    const json: WorkflowNodeJSON = {
      id: node.id,
      type: node.flowNodeType,
      meta: {
        position: { x: transform.position.x, y: transform.position.y },
        ...metaData,
      },
      data: formJSON,
    };
    return json;
  },
};
